// NFT部署脚本
// 使用前请确保安装必要的依赖: npm install ethers dotenv

const { ethers } = require('ethers');
const fs = require('fs');
require('dotenv').config();

// 配置信息
const config = {
    // NFT基本信息
    NFT_NAME: "MyLearningNFT",
    NFT_SYMBOL: "MLN",
    BASE_URI: "ipfs://", // IPFS基础URI
    MAX_SUPPLY: 1000, // 最大供应量
    MAX_MINT_PER_ADDRESS: 10, // 每个地址最大铸造数量

    // 网络配置
    SEPOLIA_RPC_URL: process.env.SEPOLIA_RPC_URL || "https://sepolia.infura.io/v3/YOUR_INFURA_PROJECT_ID",
    PRIVATE_KEY: process.env.PRIVATE_KEY,

    // Gas配置
    GAS_LIMIT: 5000000,
    GAS_PRICE: ethers.utils.parseUnits('20', 'gwei')
};

// 合约ABI（简化版，只包含部署和基本功能）
const contractABI = [
    "constructor(string memory _name, string memory _symbol, string memory _baseURI, uint256 _maxSupply, uint256 _maxMintPerAddress)",
    "function name() public view returns (string)",
    "function symbol() public view returns (string)",
    "function totalSupply() public view returns (uint256)",
    "function mintNFT(address to, string memory tokenURI) public payable returns (uint256)",
    "function tokenURI(uint256 tokenId) public view returns (string)",
    "function ownerOf(uint256 tokenId) public view returns (address)",
    "function balanceOf(address owner) public view returns (uint256)",
    "function tokensOfOwner(address owner) public view returns (uint256[])",
    "function owner() public view returns (address)",
    "event Transfer(address indexed from, address indexed to, uint256 indexed tokenId)",
    "event NFTMinted(address indexed to, uint256 indexed tokenId, string tokenURI)"
];

// 请将编译后的字节码粘贴到这里
const contractBytecode = `
请将您编译后的NFT合约字节码粘贴到这里。
您可以使用以下方式获取字节码：
1. 使用 Remix IDE 编译合约
2. 使用 Hardhat: npx hardhat compile
3. 使用 Truffle: truffle compile
`;

async function deployNFTContract() {
    try {
        console.log("🎨 开始部署 NFT 合约到 Sepolia 测试网...\n");

        // 检查环境变量
        if (!config.PRIVATE_KEY) {
            throw new Error("请设置 PRIVATE_KEY 环境变量");
        }

        // 连接到测试网
        const provider = new ethers.providers.JsonRpcProvider(config.SEPOLIA_RPC_URL);
        const wallet = new ethers.Wallet(config.PRIVATE_KEY, provider);

        console.log("📡 连接信息:");
        console.log("- 网络:", await provider.getNetwork());
        console.log("- 部署地址:", wallet.address);
        console.log("- 余额:", ethers.utils.formatEther(await wallet.getBalance()), "ETH\n");

        // 创建合约工厂
        const contractFactory = new ethers.ContractFactory(
            contractABI,
            contractBytecode,
            wallet
        );

        console.log("🎨 NFT 参数:");
        console.log("- 名称:", config.NFT_NAME);
        console.log("- 符号:", config.NFT_SYMBOL);
        console.log("- 基础URI:", config.BASE_URI);
        console.log("- 最大供应量:", config.MAX_SUPPLY);
        console.log("- 每地址最大铸造:", config.MAX_MINT_PER_ADDRESS, "\n");

        // 部署合约
        console.log("⏳ 正在部署NFT合约...");
        const contract = await contractFactory.deploy(
            config.NFT_NAME,
            config.NFT_SYMBOL,
            config.BASE_URI,
            config.MAX_SUPPLY,
            config.MAX_MINT_PER_ADDRESS,
            {
                gasLimit: config.GAS_LIMIT,
                gasPrice: config.GAS_PRICE
            }
        );

        console.log("🔄 等待交易确认...");
        console.log("- 交易哈希:", contract.deployTransaction.hash);

        await contract.deployed();

        console.log("\n✅ NFT合约部署成功!");
        console.log("- 合约地址:", contract.address);
        console.log("- 区块号:", contract.deployTransaction.blockNumber);

        // 验证合约
        console.log("\n🔍 验证合约信息:");
        const name = await contract.name();
        const symbol = await contract.symbol();
        const totalSupply = await contract.totalSupply();
        const owner = await contract.owner();

        console.log("- NFT名称:", name);
        console.log("- NFT符号:", symbol);
        console.log("- 当前供应量:", totalSupply.toString());
        console.log("- 合约所有者:", owner);

        // 保存部署信息
        const deploymentInfo = {
            contractAddress: contract.address,
            deploymentHash: contract.deployTransaction.hash,
            deploymentBlock: contract.deployTransaction.blockNumber,
            deployer: wallet.address,
            network: "sepolia",
            timestamp: new Date().toISOString(),
            nftInfo: {
                name,
                symbol,
                totalSupply: totalSupply.toString(),
                owner
            }
        };

        fs.writeFileSync(
            'nft-deployment-info.json',
            JSON.stringify(deploymentInfo, null, 2)
        );

        console.log("\n📄 部署信息已保存到 nft-deployment-info.json");

        // 生成OpenSea链接
        console.log("\n🌊 OpenSea 测试网链接:");
        console.log("- 合约:", `https://testnets.opensea.io/assets/sepolia/${contract.address}`);

        console.log("\n🔗 Etherscan 链接:");
        console.log("- 合约:", `https://sepolia.etherscan.io/address/${contract.address}`);
        console.log("- 交易:", `https://sepolia.etherscan.io/tx/${contract.deployTransaction.hash}`);

        return contract;

    } catch (error) {
        console.error("❌ 部署失败:", error.message);
        throw error;
    }
}

// 铸造NFT的示例函数
async function mintExampleNFT(contractAddress, recipientAddress, metadataURI) {
    try {
        console.log("\n🎨 开始铸造示例NFT...");

        const provider = new ethers.providers.JsonRpcProvider(config.SEPOLIA_RPC_URL);
        const wallet = new ethers.Wallet(config.PRIVATE_KEY, provider);

        // 连接到已部署的合约
        const contract = new ethers.Contract(contractAddress, contractABI, wallet);

        // 铸造NFT
        console.log("⏳ 正在铸造NFT...");
        const tx = await contract.mintNFT(recipientAddress, metadataURI, {
            gasLimit: 500000,
            gasPrice: config.GAS_PRICE
        });

        console.log("🔄 等待交易确认...");
        const receipt = await tx.wait();

        // 从事件中获取Token ID
        const mintEvent = receipt.events?.find(event => event.event === 'NFTMinted');
        const tokenId = mintEvent?.args?.tokenId;

        console.log("\n✅ NFT铸造成功!");
        console.log("- Token ID:", tokenId?.toString());
        console.log("- 接收者:", recipientAddress);
        console.log("- 元数据URI:", metadataURI);
        console.log("- 交易哈希:", tx.hash);

        console.log("\n🌊 在OpenSea查看:");
        console.log(`https://testnets.opensea.io/assets/sepolia/${contractAddress}/${tokenId}`);

        return tokenId;

    } catch (error) {
        console.error("❌ 铸造失败:", error.message);
        throw error;
    }
}

// 批量铸造NFT的示例函数 - 使用你的metadata数组
async function batchMintFromMetadataArray(contractAddress, recipientAddress, metadataHashPrefix) {
    try {
        console.log("\n🎨 开始批量铸造NFT...");

        const provider = new ethers.providers.JsonRpcProvider(config.SEPOLIA_RPC_URL);
        const wallet = new ethers.Wallet(config.PRIVATE_KEY, provider);

        // 连接到已部署的合约
        const contract = new ethers.Contract(contractAddress, contractABI, wallet);

        // 读取你的metadata文件并为每个NFT创建URI
        // 假设你上传metadata后得到的hash是metadataHashPrefix
        const metadataURIs = [
            `ipfs://${metadataHashPrefix}#0`, // myNFT1
            `ipfs://${metadataHashPrefix}#1`, // myNFT2  
            `ipfs://${metadataHashPrefix}#2`, // myNFT3
            `ipfs://${metadataHashPrefix}#3`, // myNFT4
            `ipfs://${metadataHashPrefix}#4`  // myNFT5
        ];

        console.log("⏳ 正在批量铸造NFT...");
        const tx = await contract.batchMintNFT(recipientAddress, metadataURIs, {
            gasLimit: 2000000, // 更高的gas限制用于批量操作
            gasPrice: config.GAS_PRICE
        });

        console.log("🔄 等待交易确认...");
        const receipt = await tx.wait();

        // 从事件中获取所有Token ID
        const mintEvents = receipt.events?.filter(event => event.event === 'NFTMinted');
        const tokenIds = mintEvents?.map(event => event.args?.tokenId.toString());

        console.log("\n✅ 批量NFT铸造成功!");
        console.log("- 铸造数量:", tokenIds?.length || 0);
        console.log("- Token IDs:", tokenIds?.join(', '));
        console.log("- 接收者:", recipientAddress);
        console.log("- 交易哈希:", tx.hash);

        console.log("\n🌊 在OpenSea查看:");
        tokenIds?.forEach((tokenId, index) => {
            console.log(`- NFT ${index + 1}: https://testnets.opensea.io/assets/sepolia/${contractAddress}/${tokenId}`);
        });

        return tokenIds;

    } catch (error) {
        console.error("❌ 批量铸造失败:", error.message);
        throw error;
    }
}

// 运行部署脚本
if (require.main === module) {
    deployNFTContract()
        .then((contract) => {
            console.log("\n🎉 NFT合约部署完成!");
            console.log("\n💡 下一步:");
            console.log("1. 准备图片并上传到IPFS");
            console.log("2. 创建JSON元数据并上传到IPFS");
            console.log("3. 使用mintNFT函数铸造您的第一个NFT");
            process.exit(0);
        })
        .catch((error) => {
            console.error("部署失败:", error);
            process.exit(1);
        });
}

module.exports = { deployNFTContract, mintExampleNFT, config };
